/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.elcom.emocbc;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.PropertyConfigurator;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author GiangLT
 */
public class CbmTool {

    public final static String MODULE_NAME = "cbm-tool";
    public final static String BASE_FOLDER = System.getProperty("user.home") + java.io.File.separator;
    public final static String LOG_FOLDER = BASE_FOLDER + "log" + java.io.File.separator + MODULE_NAME + java.io.File.separator;
    public final static String CONFIG_FOLDER = BASE_FOLDER + "config" + java.io.File.separator + MODULE_NAME + java.io.File.separator;
    public Logger logger;
    private static final int CHUNK_LENGTH = 79;
    Map<Byte, Cbm> msgIdmap = new TreeMap<Byte, Cbm>();
    LinkedList<byte[]> parsedCbms = new LinkedList<byte[]>();
    static final String CBM_FOLDER = "H:\\New folder\\test";
    static final String CBM_ERROR_FOLDER = "H:\\New folder\\test\\PACKET_error";
    final String OUTPUT_FILE = "H:\\New folder\\test\\cbms.xls";
    private Workbook workbook;

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        PropertyConfigurator.configureAndWatch(CONFIG_FOLDER + MODULE_NAME + "-log4j.props");

        CbmTool cbmTool = new CbmTool();
        cbmTool.doProcess();

        //<editor-fold defaultstate="collapsed" desc="old flow">
        //        File folder = new File(CBM_FOLDER);
        //        File[] cbmFiles = folder.listFiles();
        //        Arrays.sort(cbmFiles, new Comparator<File>() {
        //            @Override
        //            public int compare(File o1, File o2) {
        //                return o1.getName().compareTo(o2.getName());
        //            }
        //        });
        //
        //        Map<String, String> shortcodeMap = new TreeMap<String, String>();
        //        Map<Byte, Cbm> msgIdmap = new TreeMap<Byte, Cbm>();
        //        LinkedList<byte[]> parsedCbms = new LinkedList<byte[]>();
        //
        //        for (File file : cbmFiles) {
        //            if (file.isFile()) {
        //                logger.info("Checking file " + file.getName());
        //                try {
        //
        //
        //                    //<editor-fold defaultstate="collapsed" desc="old flow">
        //                    byte pageIndicator = normalizedCbmArray[1];
        //                    String pageIndicatorString = Integer.toBinaryString(pageIndicator);
        //                    if (pageIndicatorString.length() == 5) {
        //                        logger.info("File: " + file.getName());
        //
        //                        String menuCountString = toHexString(normalizedCbmArray[4]);
        //                        logger.info("Menu count: " + menuCountString);
        //
        //
        //                        StringBuilder shortcode = new StringBuilder("abc");
        //                        if (menuCountString.startsWith("1")) {
        //
        //                            byte shortCodeByteLength = normalizedCbmArray[7];
        //                            if (shortCodeByteLength != 0x00) {
        //                                shortcode = new StringBuilder();
        //                                shortcode.append(toHexString(normalizedCbmArray[9]));
        //                                shortcode.append(toHexString(normalizedCbmArray[10]));
        //                            }
        //
        //
        //                        } else if (menuCountString.startsWith("0")) {
        //
        //                            byte shortCodeByteLength = normalizedCbmArray[6];
        //                            if (shortCodeByteLength != 0x00) {
        //                                shortcode = new StringBuilder();
        //                                shortcode.append(toHexString(normalizedCbmArray[8]));
        //                                shortcode.append(toHexString(normalizedCbmArray[9]));
        //                            }
        //                        } else {
        //                            logger.info("Unknown menu count string: " + menuCountString);
        //                            shortcode = new StringBuilder("Unknown");
        //                        }
        //
        //                        StringBuilder standardShortcode = new StringBuilder();
        //                        standardShortcode.append(shortcode.charAt(1));
        //                        standardShortcode.append(shortcode.charAt(0));
        //                        standardShortcode.append(shortcode.charAt(3));
        //                        standardShortcode.append(shortcode.charAt(2));
        //
        //                        if (!shortcodeMap.containsKey(standardShortcode.toString())) {
        //                            shortcodeMap.put(standardShortcode.toString(), menuCountString);
        //                        }
        //                        logger.info("Shortcode: " + shortcode);
        //
        //                    }
        //                    //</editor-fold>
        //
        //
        //                } catch (Exception ex) {
        //                    Logger.getLogger(CbmTool.class.getName()).log(Level.SEVERE, null, ex);
        //                }
        //            }
        //        }
        //
        ////        Set<Entry<String, String>> entrySet = shortcodeMap.entrySet();
        ////        for (Entry<String, String> entry : entrySet) {
        ////            logger.info(entry.getKey() + ": " + entry.getValue());
        ////        }
        //</editor-fold>
    }

    public void doProcess() {
        logger = LoggerFactory.getLogger(CbmTool.class);

        File folder = new File(CBM_FOLDER);
        File[] cbmFiles = folder.listFiles();
        Arrays.sort(cbmFiles, new Comparator<File>() {
            @Override
            public int compare(File o1, File o2) {
                return o1.getName().compareTo(o2.getName());
            }
        });

        workbook = new HSSFWorkbook();
        File errorFolder = new File(CBM_ERROR_FOLDER);
        if (!errorFolder.exists()) {
            errorFolder.mkdir();
        }

        for (File file : cbmFiles) {
            if (file.isFile()) {
                logger.info("=============================================");
                logger.info("Checking file {}", file.getName());
                try {

                    byte[] cbmArray = IOUtils.toByteArray(new FileInputStream(file));
                    byte[] normalizedCbmArray = Arrays.copyOfRange(cbmArray, 0, cbmArray.length);
                    byte msgId = normalizedCbmArray[0];
                    byte pageIndicator = normalizedCbmArray[1];
                    logger.info("MsgID: {}, PageId: {}", toHexString(msgId), toHexString(pageIndicator));

//                    logger.info("Checking whether cbm is parsed or not");
                    byte[] cbmArrayToCompare = Arrays.copyOfRange(normalizedCbmArray, 2, cbmArray.length);
                    boolean parsed = false;
                    for (byte[] cbm : parsedCbms) {
                        if (Arrays.equals(cbm, cbmArrayToCompare)) {
                            parsed = true;
//                            logger.info("CBM is already parsed, so ignoring it");
                            break;
                        }
                    }

                    if (parsed) {
//                        logger.info("Parsed CBM: " + toHexString(normalizedCbmArray));
                        continue;
                    }
                    parsedCbms.addFirst(cbmArrayToCompare);

                    Cbm cbm;
                    if (msgIdmap.containsKey(msgId)) {
//                        logger.info("Found 1 partial parsed CBM with Id " + toHexString(msgId));
                        cbm = msgIdmap.get(msgId);
                    } else {
                        cbm = new Cbm();
                        cbm.setMsgId(msgId);

                    }

                    cbm.setPageIndicator(pageIndicator);

                    Short numOfPages = new Short(toHexString(pageIndicator).substring(1, 2));
                    cbm.setNumOfPages(numOfPages);

                    Short pageNum = new Short(toHexString(pageIndicator).substring(0, 1));
                    cbm.getPageNums().add(pageNum);

                    byte[] fullCbm = cbm.getFullCbm();
                    if (fullCbm == null) {
                        fullCbm = new byte[numOfPages * CHUNK_LENGTH]; // no header, no EOF, no msgId, no pageIndicator
                    }

                    final int startIndexOfContent = 2;
//                    final int endIndexOfContent = normalizedCbmArray.length - 1;
//                    final int contentLength = endIndexOfContent - startIndexOfContent + 1;

                    System.arraycopy(normalizedCbmArray, startIndexOfContent, fullCbm, (pageNum - 1) * CHUNK_LENGTH, CHUNK_LENGTH);
                    cbm.setFullCbm(fullCbm);
                    msgIdmap.put(msgId, cbm);

                    if (cbm.getPageNums().size() == numOfPages) {
                        parseCbm(cbm);
//                        if (cbm.getIndicators() == null || cbm.getIndicators().length == 0) {
                        printCbm(cbm);
//                        }
                    }

                } catch (Exception ex) {
                    logger.error("", ex);
                    logger.error("Copying file {} to error folder", file.getName());
                    try {
                        FileUtils.copyFileToDirectory(file, errorFolder);
                    } catch (IOException ex1) {
                        logger.error("Cannot copy to error folder", ex1);
                    }
                }
//            }
            }
        }

        FileOutputStream fileOut = null;
        try {
            fileOut = new FileOutputStream(OUTPUT_FILE);
            workbook.write(fileOut);
            fileOut.close();
        } catch (Exception ex) {
            logger.error("", ex);
        } finally {
            IOUtils.closeQuietly(fileOut);
        }

//        Collection<Cbm> cbms = msgIdmap.values();
//        for (Cbm cbm : cbms) {
//            try {
//                if (cbm.getPageNums().size() == cbm.getNumOfPages()) {
//                    printCbm(cbm);
//                }
//            } catch (Exception ex) {
//                logger.error("", ex);
//            }
//        }
    }

//    public Short toShort(byte[] b) {
//        toHexString(b)
//    }
    public Integer toInt(byte b) {
//        byte[] byteArray = new byte[]{b};
//        return toShort(byteArray);
        return Integer.parseInt(toHexString(b), 16);
    }

    public static String toHexString(byte b) {
        return String.format("%02X", b);
    }

    public static String toHexString(byte[] byteArray) {
        StringBuilder sb = new StringBuilder();
        for (byte b : byteArray) {
            sb.append(toHexString(b)).append(" ");
        }
        return sb.toString();
    }

    public String toString(byte[] byteArray) {
        return new String(byteArray);
    }

    public String toString(byte b) {
        return new String(new byte[]{b});
    }

    private void parseCbm(Cbm cbm) {

        byte[] cbmArray = cbm.getFullCbm();
        logger.info("Parsing CBM: " + toHexString(cbmArray));
        int cursor = 0;

        cbm.setMsgLength(cbmArray[cursor++]);// verify later 
        cbm.setActionCode(cbmArray[cursor++]);

        byte menuCount = cbmArray[cursor++];
        int first = Integer.parseInt(toHexString(menuCount).substring(0, 1));
        if (first == 1) {
            cbm.setTopicId1(new byte[]{cbmArray[cursor++], cbmArray[cursor++]});
        } else {
            cbm.setTopicId1(new byte[]{cbmArray[cursor++]});
        }
        cbm.setNumOfMenus(menuCount);
        //<editor-fold defaultstate="collapsed" desc="Default Item">
        DefaultItem defaultItem = new DefaultItem();
        defaultItem.setDefaultShortCodeLength(cbmArray[cursor++]);
//        Short defaultShortCodeLength = new Short(toHexString(defaultItem.getDefaultShortCodeLength()));
        Integer defaultShortCodeLength = toInt(defaultItem.getDefaultShortCodeLength());

        byte[] defaultShortCode = new byte[defaultShortCodeLength];
        System.arraycopy(cbmArray, cursor, defaultShortCode, 0, defaultShortCodeLength);
        defaultItem.setDefaultShortCode(defaultShortCode);
        cursor += defaultShortCodeLength;

        defaultItem.setDefaultSyntaxLength(cbmArray[cursor++]);
//        Short defaultSyntaxLength = new Short(toHexString(defaultItem.getDefaultSyntaxLength()));
        Integer defaultSyntaxLength = toInt(defaultItem.getDefaultSyntaxLength());

        byte[] defaulSyntax = new byte[defaultSyntaxLength];
        System.arraycopy(cbmArray, cursor, defaulSyntax, 0, defaultSyntaxLength);
        defaultItem.setDefaultSyntax(defaulSyntax);
        cursor += defaultSyntaxLength;

        cbm.setDefaultItem(defaultItem);
        //</editor-fold>

        //<editor-fold defaultstate="collapsed" desc="Indicator">
        byte[] indicator = new byte[Cbm.INDICATORS1.length];
        System.arraycopy(cbmArray, cursor, indicator, 0, Cbm.INDICATORS1.length);
        if (!Arrays.equals(indicator, Cbm.INDICATORS1) && !Arrays.equals(indicator, Cbm.INDICATORS2)) {
            logger.info("WARN: 6 indicator bytes not match " + toHexString(indicator));
        } else {
            cbm.setIndicators(indicator);
            cursor += Cbm.INDICATORS1.length;
            cbm.setTopicId2(cbmArray[cursor++]);
        }

        //</editor-fold>
        //<editor-fold defaultstate="collapsed" desc="Menu Items">
        int numOfMenus = Integer.parseInt(toHexString(menuCount).substring(1, 2));
        if (cbm.getIndicators() != null && cbm.getIndicators().length > 0) {
            numOfMenus -= 1;
        }

        List<MenuItem> menuItems = new LinkedList<MenuItem>();
        for (int i = 0; i < numOfMenus; i++) {
            MenuItem menuItem = new MenuItem();
            menuItem.setShortCodeLength(cbmArray[cursor++]);
            int shortCodeLength = new Short(toHexString(menuItem.getShortCodeLength()).substring(1, 2));

            byte[] shortCode = new byte[shortCodeLength];
            System.arraycopy(cbmArray, cursor, shortCode, 0, shortCodeLength);
            menuItem.setShortCode(shortCode);
            cursor += shortCodeLength;

            menuItem.setSyntaxLength(cbmArray[cursor++]);
            logger.debug("Syntax Length byte: " + toHexString(menuItem.getSyntaxLength()));
//            Short syntaxLength = new Short(toHexString(menuItem.getSyntaxLength()));
            Integer syntaxLength;
            char firstChar = toHexString(menuItem.getSyntaxLength()).charAt(0);
            if (firstChar == '8') {
                syntaxLength = Integer.parseInt(toHexString(menuItem.getSyntaxLength()).substring(1, 2), 16);
                logger.debug("8 is the first bit => syntaxLength = {}", syntaxLength);
            } else {
                syntaxLength = toInt(menuItem.getSyntaxLength());
                logger.debug("8 is NOT the first bit => syntaxLength = {}", syntaxLength);
            }

            byte[] syntax = new byte[syntaxLength];
            System.arraycopy(cbmArray, cursor, syntax, 0, syntaxLength);
            menuItem.setSyntax(syntax);
            cursor += syntaxLength;

            menuItem.setTitleLength(cbmArray[cursor++]);
//            Short titleLength = new Short(toHexString(menuItem.getTitleLength()));
            Integer titleLength = toInt(menuItem.getTitleLength());

            byte[] title = new byte[titleLength];
            System.arraycopy(cbmArray, cursor, title, 0, titleLength);
            menuItem.setTitle(title);
            cursor += titleLength;

            menuItems.add(menuItem);
        }
        cbm.setMenuItems(menuItems);
        //</editor-fold>

        //<editor-fold defaultstate="collapsed" desc="Separators">
        byte[] separator = new byte[Cbm.SEPARATORS.length];
        System.arraycopy(cbmArray, cursor, separator, 0, Cbm.SEPARATORS.length);
        cbm.setSeparators(separator);
        cursor += Cbm.SEPARATORS.length;
        //</editor-fold>

        //<editor-fold defaultstate="collapsed" desc="Content">
        cbm.setContentLength(cbmArray[cursor++]);
        Integer contentLength = toInt(cbm.getContentLength());

        byte[] content = new byte[contentLength];
        System.arraycopy(cbmArray, cursor, content, 0, contentLength);
        cbm.setContent(content);
        //</editor-fold>

    }

    private void printCbm(Cbm cbm) {
        Sheet sheet = workbook.createSheet();
        int rowIdx = 0;
        Row row = sheet.createRow(rowIdx++);
        row.createCell(0).setCellValue("Field");
        row.createCell(1).setCellValue("Byte Value");
        row.createCell(2).setCellValue("Description");

        row = sheet.createRow(rowIdx++);
        row.createCell(0).setCellValue("CBM");
        row.createCell(2).setCellValue(toHexString(cbm.getFullCbm()));
        logger.info("CBM: " + toHexString(cbm.getFullCbm()));

        logger.info("----------------------------------------------------");
        row = sheet.createRow(rowIdx++);
        row.createCell(0).setCellValue("General 1:");
        logger.info("General 1:");

        row = sheet.createRow(rowIdx++);
        row.createCell(0).setCellValue("    Msg Id");
        row.createCell(1).setCellValue(toHexString(cbm.getMsgId()));
        logger.info("    Msg Id: " + toHexString(cbm.getMsgId()));

//        Row row4 = sheet.createRow(rowIdx++);
//        row4.createCell(0).setCellValue("    Page Indicator");
//        row4.createCell(1).setCellValue(toHexString(cbm.getPageIndicator()));
        logger.info("    Page Indicator: " + toHexString(cbm.getPageIndicator()));

        row = sheet.createRow(rowIdx++);
        row.createCell(0).setCellValue("    Msg Length");
        row.createCell(1).setCellValue(toHexString(cbm.getMsgLength()));
        row.createCell(2).setCellValue(toInt(cbm.getMsgLength()));
        logger.info("    Msg Length: " + toHexString(cbm.getMsgLength()));

        row = sheet.createRow(rowIdx++);
        row.createCell(0).setCellValue("    Action Code");
        row.createCell(1).setCellValue(toHexString(cbm.getActionCode()));
        logger.info("    Action Code: " + toHexString(cbm.getActionCode()));

        row = sheet.createRow(rowIdx++);
        row.createCell(0).setCellValue("    Num Of Menus");
        row.createCell(1).setCellValue(toHexString(cbm.getNumOfMenus()));
//        row.createCell(2).setCellValue();
        logger.info("    Num Of Menus: " + toHexString(cbm.getNumOfMenus()));

        row = sheet.createRow(rowIdx++);
        row.createCell(0).setCellValue("    Topic Id1");
        row.createCell(1).setCellValue(toHexString(cbm.getTopicId1()));
        logger.info("    Topic Id1: " + toHexString(cbm.getTopicId1()));
        logger.info("----------------------------------------------------");

        logger.info("----------------------------------------------------");

        row = sheet.createRow(rowIdx++);
        row.createCell(0).setCellValue("Default Item");
        logger.info("Default Item:");

        row = sheet.createRow(rowIdx++);
        row.createCell(0).setCellValue("    DefaultShortCodeLength");
        row.createCell(1).setCellValue(toHexString(cbm.getDefaultItem().getDefaultShortCodeLength()));
        row.createCell(2).setCellValue(toInt(cbm.getDefaultItem().getDefaultShortCodeLength()));
        logger.info("    DefaultShortCodeLength: " + toHexString(cbm.getDefaultItem().getDefaultShortCodeLength()));

        row = sheet.createRow(rowIdx++);
        row.createCell(0).setCellValue("    DefaultShortCode");
        row.createCell(1).setCellValue(toHexString(cbm.getDefaultItem().getDefaultShortCode()));
//        row.createCell(2).setCellValue();
        logger.info("    DefaultShortCode: " + toHexString(cbm.getDefaultItem().getDefaultShortCode()));

        row = sheet.createRow(rowIdx++);
        row.createCell(0).setCellValue("    DefaultSyntaxLength");
        row.createCell(1).setCellValue(toHexString(cbm.getDefaultItem().getDefaultSyntaxLength()));
        row.createCell(2).setCellValue(toInt(cbm.getDefaultItem().getDefaultSyntaxLength()));
        logger.info("    DefaultSyntaxLength: " + toHexString(cbm.getDefaultItem().getDefaultSyntaxLength()));

        row = sheet.createRow(rowIdx++);
        row.createCell(0).setCellValue("    DefaultSyntax");
        row.createCell(1).setCellValue(toHexString(cbm.getDefaultItem().getDefaultSyntax()));
        row.createCell(2).setCellValue(toString(cbm.getDefaultItem().getDefaultSyntax()));
        logger.info("    DefaultSyntax: " + toHexString(cbm.getDefaultItem().getDefaultSyntax()));
        logger.info("----------------------------------------------------");

        logger.info("----------------------------------------------------");

        row = sheet.createRow(rowIdx++);
        row.createCell(0).setCellValue("General 2");
        logger.info("General 2:");

        row = sheet.createRow(rowIdx++);
        row.createCell(0).setCellValue("    Indicator");
        if (cbm.getIndicators() != null) {
            row.createCell(1).setCellValue(toHexString(cbm.getIndicators()));
            logger.info("    Indicator: " + toHexString(cbm.getIndicators()));

            row = sheet.createRow(rowIdx++);
            row.createCell(0).setCellValue("    COS");
            row.createCell(1).setCellValue(toHexString(cbm.getTopicId2()));
            logger.info("    COS: " + toHexString(cbm.getTopicId2()));
        } else {
            logger.error(" Indicator is null");
            row = sheet.createRow(rowIdx++);
            row.createCell(0).setCellValue("    COS");
            logger.info("    COS: ");
        }

        logger.info("----------------------------------------------------");

        for (MenuItem menuItem : cbm.getMenuItems()) {
            logger.info("----------------------------------------------------");

            row = sheet.createRow(rowIdx++);
            row.createCell(0).setCellValue("Menu Item");
            logger.info("Menu Item:");

            row = sheet.createRow(rowIdx++);
            row.createCell(0).setCellValue("    ShortCodeLength");
            row.createCell(1).setCellValue(toHexString(menuItem.getShortCodeLength()));
//            row.createCell(2).setCellValue(toInt(menuItem.getShortCodeLength()));
            logger.info("    ShortCodeLength: " + toHexString(menuItem.getShortCodeLength()));

            row = sheet.createRow(rowIdx++);
            row.createCell(0).setCellValue("    ShortCode");
            row.createCell(1).setCellValue(toHexString(menuItem.getShortCode()));
//            row.createCell(2).setCellValue();
            logger.info("    ShortCode: " + toHexString(menuItem.getShortCode()));

            row = sheet.createRow(rowIdx++);
            row.createCell(0).setCellValue("    SyntaxLength");
            row.createCell(1).setCellValue(toHexString(menuItem.getSyntaxLength()));
//            row.createCell(2).setCellValue(toInt(menuItem.getSyntaxLength()));
            logger.info("    SyntaxLength: " + toHexString(menuItem.getSyntaxLength()));

            row = sheet.createRow(rowIdx++);
            row.createCell(0).setCellValue("    Syntax");
            if (menuItem.getSyntax() != null) {
                row.createCell(1).setCellValue(toHexString(menuItem.getSyntax()));
                row.createCell(2).setCellValue(toString(menuItem.getSyntax()));
                logger.info("    Syntax: " + toHexString(menuItem.getSyntax()));
            } else {
                logger.error("INFO: Syntax is null");
            }

            row = sheet.createRow(rowIdx++);
            row.createCell(0).setCellValue("    TitleLength");
            row.createCell(1).setCellValue(toHexString(menuItem.getTitleLength()));
            row.createCell(2).setCellValue(toInt(menuItem.getTitleLength()));
            logger.info("    TitleLength: " + toHexString(menuItem.getTitleLength()));

            row = sheet.createRow(rowIdx++);
            row.createCell(0).setCellValue("    Title");
            row.createCell(1).setCellValue(toHexString(menuItem.getTitle()));
            row.createCell(2).setCellValue(toString(menuItem.getTitle()));
            logger.info("    Title: " + toHexString(menuItem.getTitle()));
            logger.info("----------------------------------------------------");
        }
        logger.info("----------------------------------------------------");

        row = sheet.createRow(rowIdx++);
        row.createCell(0).setCellValue("Content");
        logger.info("Content:");

        row = sheet.createRow(rowIdx++);
        row.createCell(0).setCellValue("    Separator");
        if (cbm.getSeparators() != null) {
            row.createCell(1).setCellValue(toHexString(cbm.getSeparators()));
            logger.info("    Separator: " + toHexString(cbm.getSeparators()));
        } else {
            logger.error("ERROR: Separator is null!");
        }

        row = sheet.createRow(rowIdx++);
        row.createCell(0).setCellValue("    ContentLength");
        row.createCell(1).setCellValue(toHexString(cbm.getContentLength()));
        row.createCell(2).setCellValue(toInt(cbm.getContentLength()));
        logger.info("    ContentLength: " + toHexString(cbm.getContentLength()));

        row = sheet.createRow(rowIdx++);
        row.createCell(0).setCellValue("    Content");
        if (cbm.getContent() != null) {
            row.createCell(1).setCellValue(toHexString(cbm.getContent()));
            row.createCell(2).setCellValue(toString(cbm.getContent()));
            logger.info("    Content: " + toHexString(cbm.getContent()));
            logger.warn("Content String {}", toString(cbm.getContent()));
        } else {
            logger.error("ERROR: content is null!");
        }
        logger.info("----------------------------------------------------");

        logger.info("====================================================");
        logger.info("====================================================");

        sheet.autoSizeColumn(0);
        sheet.setColumnWidth(1, 10000);
    }
}
